/*
 * twim.c
 *
 *  Created on: Aug 1, 2013
 *      Author: Ken Arok
 *
 *      Revision history:
 *      ---------------------------------------------------------
 *      Date			|	Revised by		|	Description
 *      ---------------------------------------------------------
 *      1. Aug 1, 2013	|	Yosef			| New establishment
 *
 *
 * \file
 *
 * \brief Hardware Abstraction Layer of Two Wire Interface Master UC3C0512C
 *
 * Copyright (c) 2013 PT Hanindo Automation Solutions. All rights reserved.
 *
 */

#include "config_board.h"

#if BOARD_1_0_USED

#include <stdio.h>
#include <string.h>
#include <avr32/io.h>

#include "compiler.h"

#include "gpio.h" // Have to include gpio.h before FreeRTOS.h as long as FreeRTOS
                  // redefines the inline keyword to empty.

#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"

#include "intc.h"
#include "twim.h"

//! \internal Pointer to the instance 1 of the TWIM registers for IT.
static volatile avr32_twim_t *twim_inst;
//! \internal Pointer to the applicative TWI transmit buffer.
static const volatile uint8_t  *twim_tx_data = NULL;
//! \internal Pointer to the applicative TWI receive buffer.
static volatile uint8_t *twim_rx_data = NULL;
//! \internal Status of the bus transfer
static volatile twim_transfer_status_t transfer_status;
//! \internal Remaining number of bytes to transmit.
static volatile uint32_t twim_tx_nb_bytes = 0;
//! \internal Remaining number of bytes to receive.
static volatile uint32_t twim_rx_nb_bytes = 0;
//! \internal IT mask.
static volatile uint32_t twim_it_mask;
//! \internal Pointer to twim package
static volatile const twim_package_t *twim_package;
//! \internal If Internal Address access is used
static volatile bool twim_next =false;

/* The semaphore used by the TWIM ISR. */
static xSemaphoreHandle xTWIMSemaphore = NULL;

/* Interrupt Serive Routine. */
void vTWIM_ISR(void);



/**
 * \internal
 * \brief TWI interrupt handler.
 * ISR(twim_master_interrupt_handler, CONF_TWIM_IRQ_GROUP,CONF_TWIM_IRQ_LEVEL)
 */
__attribute__((__noinline__)) static long prvTWIM_ISR_NonNakedBehaviour(void)
{
	uint32_t status;
	long xSwitchRequired = false;

	/* Get masked status register value. */
	status = twim_inst->sr & twim_it_mask;
	/* This is a NACK. */
	if (status & AVR32_TWIM_SR_STD_MASK) {
		/* If we get a nack, clear the valid bit in cmdr,
		otherwise the command will be resent. */
		transfer_status =(status & AVR32_TWIM_IER_NAK_MASK) ?
							TWI_RECEIVE_NACK : TWI_ARBITRATION_LOST;
		twim_inst->CMDR.valid = 0;
		twim_inst->scr = ~0UL;
		twim_inst->idr = ~0UL;
		twim_next = false;
	}
	/* This is a RXRDY. */
	else if (status & AVR32_TWIM_SR_RXRDY_MASK) {
		/* Get data from Receive Holding Register. */
		*twim_rx_data = twim_inst->rhr;
		twim_rx_data++;
		/* Decrease received bytes number. */
		twim_rx_nb_bytes--;
		/* Receive complete. */
		if (twim_rx_nb_bytes == 0) {
			/* Finish the receive operation. */
			twim_inst->idr = AVR32_TWIM_IDR_RXRDY_MASK;
			/* Set busy to false. */
			twim_next = false;

			portENTER_CRITICAL();
			xSemaphoreGiveFromISR(xTWIMSemaphore, &xSwitchRequired);
			portEXIT_CRITICAL();
		}
	}
	/* This is a TXRDY. */
	else if (status & AVR32_TWIM_SR_TXRDY_MASK) {
		/* No more bytes to transmit. */
		if (twim_tx_nb_bytes == 0) {
			/* Finish the receive operation. */
			twim_inst->idr = AVR32_TWIM_IDR_TXRDY_MASK;
			/* Set busy to false. */
			twim_next = false;

			portENTER_CRITICAL();
			xSemaphoreGiveFromISR(xTWIMSemaphore, &xSwitchRequired);
			portEXIT_CRITICAL();
		}
		else {
			/* Put the byte in the Transmit Holding Register. */
			twim_inst->thr = *twim_tx_data++;
			/* Decrease transmitted bytes number. */
			twim_tx_nb_bytes--;
			if (twim_tx_nb_bytes == 0) {
				/* Check for next transfer. */
				if(twim_next) {
					twim_next = false;
					twim_tx_nb_bytes = twim_package->length;
					twim_tx_data = twim_package->buffer;
				}
			}
		}
	}
	return (xSwitchRequired);
}


/*
 * The TWIM ISR.  Handles both Tx and Rx complete interrupts.
 */
__attribute__((__naked__)) void vTWIM_ISR(void)
{
	/* This ISR can cause a context switch, so the first statement must be a
	call to the portENTER_SWITCHING_ISR() macro.  This must be BEFORE any
	variable declarations. */
	portENTER_SWITCHING_ISR();

	/* The return value is used by FreeRTOS to change the context if needed after rete instruction
	in standalone use, this value should be ignored. */
	prvTWIM_ISR_NonNakedBehaviour();

	/* Exit the ISR.  If a task was woken by either a character being received
	or transmitted then a context switch will occur. */
	portEXIT_SWITCHING_ISR();
}


/**
 * \brief Set the twim bus speed in conjunction with the clock frequency
 *
 * \param twim					Base address of the TWIM (i.e. &AVR32_TWIM).
 * \param speed					The desired twim bus speed
 * \param pba_hz				The current running PBA clock frequency
 * \retval TWIM_STATUS_OK		Transaction is successful
 * \retval TWIMERR_INVALID_ARG	Invalid arg resulting in wrong CWGR Exponential
 */
twim_status_code_t twim_set_speed(volatile avr32_twim_t *twim, uint32_t speed, uint32_t pba_hz)
{
	uint32_t f_prescaled;
	uint8_t cwgr_exp = 0;
	f_prescaled = (pba_hz / speed / 2);
	/* f_prescaled must fit in 8 bits, cwgr_exp must fit in 3 bits. */
	while ((f_prescaled > 0xFF) && (cwgr_exp <= 0x7)) {
		/* Increase clock divider. */
		cwgr_exp++;
		/* divide f_prescaled value. */
		f_prescaled /= 2;
	}
	if (cwgr_exp > 0x7) {
		return TWIM_ERR_INVALID_ARG;
	}
	/* Set clock waveform generator register. */
	twim->cwgr = ((f_prescaled/2) << AVR32_TWIM_CWGR_LOW_OFFSET)
			| ((f_prescaled - f_prescaled/2) << AVR32_TWIM_CWGR_HIGH_OFFSET)
			| (cwgr_exp << AVR32_TWIM_CWGR_EXP_OFFSET)
			| (0     << AVR32_TWIM_CWGR_DATA_OFFSET)
			| (f_prescaled << AVR32_TWIM_CWGR_STASTO_OFFSET);

	return TWIM_STATUS_OK;
}

/**
 * \brief Initialize the TWIM master module
 *
 * \param twim						Base address of the TWIM (i.e. &AVR32_TWIM)
 * \param *opt						Options for initializing the twim module
 *									(see \ref twim_options_t)
 * \retval TWIM_STATUS_OK			Transaction is successful
 * \retval TWIM_ERR_INVALID_ARG		Invalid arg resulting in wrong CWGR Exponential
 * \retval TWIM_ERR_IO_ERROR		NACK is received or Bus Arbitration lost
 * \retval TWIM_ERR_ERR_NO_MEMORY	Insufficient memory.
 */
twim_status_code_t twim_master_init(volatile avr32_twim_t *twim, const twim_options_t *opt)
{
	bool global_interrupt_enabled;

	/* Create the TWIM semaphore. */
	vSemaphoreCreateBinary(xTWIMSemaphore);
	if(xTWIMSemaphore == NULL) {
		return TWIM_ERR_NO_MEMORY;
	}

	global_interrupt_enabled = cpu_irq_is_enabled();
	/* Initialize bus transfer status. */
	transfer_status = TWI_SUCCESS;
	/* Disable TWI interrupts. */
	if (global_interrupt_enabled) {
		cpu_irq_disable ();
	}
	twim->idr = ~0UL;
	/* Enable master transfer. */
	twim->cr = AVR32_TWIM_CR_MEN_MASK;
	/* Reset TWI. */
	twim->cr = AVR32_TWIM_CR_SWRST_MASK;
	if (global_interrupt_enabled) {
		cpu_irq_enable ();
	}
	/* Clear SR. */
	twim->scr = ~0UL;

	/* Register Register twim_master_interrupt_handler interrupt
	 on level CONF_TWIM_IRQ_LEVEL. */
	irqflags_t flags = cpu_irq_save();
	INTC_register_interrupt((__int_handler)&vTWIM_ISR, CONF_TWIM_IRQ_LINE, CONF_TWIM_IRQ_LEVEL);
	cpu_irq_restore(flags);

	if (opt->smbus) {
		/* Enable SMBUS Transfer. */
		twim->cr = AVR32_TWIM_CR_SMEN_MASK;
		twim->smbtr = (uint32_t) -1;
	}
	/* Select the speed. */
	if (twim_set_speed (twim, opt->speed, opt->pba_hz) == TWIM_ERR_INVALID_ARG) {
		return TWIM_ERR_INVALID_ARG;
	}
	/* Probe the component. */
	twim_probe (twim, opt->chip);
	/* Check for nack and arbitration. */
	if (transfer_status == TWI_RECEIVE_NACK || transfer_status == TWI_ARBITRATION_LOST) {
		return TWIM_ERR_IO_ERROR;
	}
	return TWIM_STATUS_OK;
}

/**
 * \brief Disable the TWI interrupts and clear its status register
 *
 * \param twim         Base address of the TWIM (i.e. &AVR32_TWI).
 */
void twim_disable_interrupt(volatile avr32_twim_t *twim)
{
	bool global_interrupt_enabled = cpu_irq_is_enabled ();
	if (global_interrupt_enabled) {
		cpu_irq_disable ();
	}
	/* Clear the interrupt flags. */
	twim->idr = ~0UL;
	/* Clear the status flags. */
	twim->scr = ~0UL;
}

/**
 * \brief Test if a chip answers for a given TWI address
 *
 * \param twim					Base address of the TWIM (i.e. &AVR32_TWIM)
 * \param chip_addr				Address of the chip which is searched for
 * \retval TWIM_STATUS_OK		Slave Found
 * \retval TWIM_ERR_IO_ERROR	ANAK received or Bus Arbitration lost
 * \retval TWIM_NO MEMORY		Insufficient memory.
 */
twim_status_code_t twim_probe (volatile avr32_twim_t *twim, uint32_t chip_addr)
{
	uint8_t data[1] = { 0 };
	return (twim_write(twim, data, 0, chip_addr, 0));
}

/**
 * \brief Read multiple bytes from a TWI compatible slave device
 *
 * \param twim					Base address of the TWIM (i.e. &AVR32_TWIM)
 * \param package				Package information and data
 *								(see \ref twim_package_t)
 * \retval TWIM_STATUS_OK		If all bytes were read successfully
 * \retval TWIM_ERR_IO_ERROR	NACK received or Bus Arbitration lost
 * \retval TWIM_ERR_TIMOUT		Peripheral is being busy.
 */
twim_status_code_t twim_read_packet(volatile avr32_twim_t *twim, const twim_package_t *package)
{
	uint8_t _timeout;

	/* Wait until peripheral is free. */
	_timeout = 100;
	while((pdFALSE == xSemaphoreTake(xTWIMSemaphore, 20)))
	{
		if(!_timeout--) {
			return TWIM_ERR_TIMEOUT;
		}
	}
	/* Disable master transfer. */
	twim->cr = AVR32_TWIM_CR_MDIS_MASK;
	/* Set pointer to TWIM instance for IT. */
	twim_inst = twim;
	/* Disable the TWIM interrupts. */
	twim_disable_interrupt (twim_inst);
	/* get a pointer to applicative data. */
	twim_rx_data = package->buffer;
	/* get a copy of nb bytes to read. */
	twim_rx_nb_bytes = package->length;
	/* Set next write transfer to false. */
	twim_next = false;
	/* Initialize bus transfer status. */
	transfer_status = TWI_SUCCESS;
	/* Check if internal address access is performed. */
	if (package->addr_length) {
		/* Reset the TWIM module to clear the THR register. */
		twim_inst->cr = AVR32_TWIM_CR_MEN_MASK;
		twim_inst->cr = AVR32_TWIM_CR_SWRST_MASK;
		twim_inst->cr = AVR32_TWIM_CR_MDIS_MASK;
		/* Selection of first valid byte of the address. */
		twim_tx_data = package->addr;
		/* Set the number of bytes to transmit. */
		twim_tx_nb_bytes = package->addr_length;
		/* Mask NACK, TXRDY and RXRDY interrupts. */
		twim_it_mask = AVR32_TWIM_IER_STD_MASK |
				AVR32_TWIM_IER_TXRDY_MASK | AVR32_TWIM_IER_RXRDY_MASK;
		/* Set the command register to initiate the transfer. */
		twim_inst->cmdr = (package->chip << AVR32_TWIM_CMDR_SADR_OFFSET)
				| (package->addr_length << AVR32_TWIM_CMDR_NBYTES_OFFSET)
				| (AVR32_TWIM_CMDR_VALID_MASK)
				| (AVR32_TWIM_CMDR_START_MASK)
				| (0 << AVR32_TWIM_CMDR_READ_OFFSET);
		/* Set the next command register to followup with the previous command. */
		twim_inst->ncmdr = ((package->chip) << AVR32_TWIM_CMDR_SADR_OFFSET)
				| (package->length << AVR32_TWIM_CMDR_NBYTES_OFFSET)
				| (AVR32_TWIM_CMDR_VALID_MASK)
				| (AVR32_TWIM_CMDR_START_MASK)
				| (AVR32_TWIM_CMDR_STOP_MASK)
				| (AVR32_TWIM_CMDR_READ_MASK);
	}
	else {
		twim_tx_nb_bytes = 0;
		/* Mask NACK and RXRDY interrupts. */
		twim_it_mask = AVR32_TWIM_IER_STD_MASK | AVR32_TWIM_IER_RXRDY_MASK;
		/* Set the command register to initiate the transfer. */
		twim_inst->cmdr = (package->chip << AVR32_TWIM_CMDR_SADR_OFFSET)
				| (package->length << AVR32_TWIM_CMDR_NBYTES_OFFSET)
				| (AVR32_TWIM_CMDR_VALID_MASK)
				| (AVR32_TWIM_CMDR_START_MASK)
				| (AVR32_TWIM_CMDR_STOP_MASK)
				| (AVR32_TWIM_CMDR_READ_MASK);
	}
	/* Update IMR through IER. */
	twim_inst->ier = twim_it_mask;
	/* Enable master transfer. */
	twim->cr = AVR32_TWIM_CR_MEN_MASK;
	/* Enable all interrupts. */
	cpu_irq_enable ();
	/* get data. */
	while (!(transfer_status) && !(twim_status ())) {
		cpu_relax();
	}
	/* Disable master transfer. */
	twim->cr = AVR32_TWIM_CR_MDIS_MASK;
	if (transfer_status == TWI_RECEIVE_NACK || transfer_status == TWI_ARBITRATION_LOST) {
		return TWIM_ERR_IO_ERROR;
	}
	return TWIM_STATUS_OK;
}

/**
 * \brief Read multiple bytes from a TWI compatible slave device
 *
 * \param twim					Base address of the TWIM (i.e. &AVR32_TWIM)
 * \param *buffer				Received data
 * \param nbytes				Number of bytes to be transmitted
 * \param saddr					Slave address
 * \param tenbit				Ten bit addressing
 * \retval STATUS_OK			If all bytes were read successfully
 * \retval TWIM_ERR_IO_ERROR	NACK received or Bus Arbitration lost
 * \retval TWIM_ERR_TIMEOUT		Peripheral is being busy.
 */
twim_status_code_t twim_read(volatile avr32_twim_t *twim, uint8_t *buffer, uint32_t nbytes, uint32_t saddr, bool tenbit)
{
	uint8_t _timeout;

	/* Wait until peripheral is free. */
	_timeout = 100;
	while((pdFALSE == xSemaphoreTake(xTWIMSemaphore, 20)))
	{
		if(!_timeout--) {
			return TWIM_ERR_TIMEOUT;
		}
	}

	/* Reset the TWIM module to clear the THR register. */
	twim->cr = AVR32_TWIM_CR_MEN_MASK;
	twim->cr = AVR32_TWIM_CR_SWRST_MASK;
	twim->cr = AVR32_TWIM_CR_MDIS_MASK;
	/* Set pointer to TWIM instance for IT. */
	twim_inst = twim;
	/* Disable the TWIM interrupts. */
	twim_disable_interrupt(twim_inst);
	/* Get a pointer to applicative data. */
	twim_rx_data = buffer;
	/* Get a copy of nb bytes to read. */
	twim_rx_nb_bytes = nbytes;
	/* Set next transfer to false. */
	twim_next = false;
	/* Initialize bus transfer status. */
	transfer_status = TWI_SUCCESS;
	/* Ten bits need special handling. */
	if (tenbit)	{
		twim_inst->cmdr = (saddr << AVR32_TWIM_CMDR_SADR_OFFSET)
				| (0 << AVR32_TWIM_CMDR_NBYTES_OFFSET)
				| (AVR32_TWIM_CMDR_VALID_MASK)
				| (AVR32_TWIM_CMDR_START_MASK)
				| (0 << AVR32_TWIM_CMDR_STOP_OFFSET)
				| (AVR32_TWIM_CMDR_TENBIT_MASK)
				| (0 << AVR32_TWIM_CMDR_READ_OFFSET);

		twim_inst->ncmdr = (saddr << AVR32_TWIM_CMDR_SADR_OFFSET)
				| (nbytes << AVR32_TWIM_CMDR_NBYTES_OFFSET)
				| (AVR32_TWIM_CMDR_VALID_MASK)
				| (AVR32_TWIM_CMDR_START_MASK)
				| (AVR32_TWIM_CMDR_STOP_MASK)
				| (AVR32_TWIM_CMDR_TENBIT_MASK)
				| (AVR32_TWIM_CMDR_REPSAME_MASK)
				| (AVR32_TWIM_CMDR_READ_MASK);
	}
	else {
		twim_inst->cmdr = (saddr << AVR32_TWIM_CMDR_SADR_OFFSET)
				| (nbytes << AVR32_TWIM_CMDR_NBYTES_OFFSET)
				| (AVR32_TWIM_CMDR_VALID_MASK)
				| (AVR32_TWIM_CMDR_START_MASK)
				| (AVR32_TWIM_CMDR_STOP_MASK)
				| (0 << AVR32_TWIM_CMDR_TENBIT_OFFSET)
				| (AVR32_TWIM_CMDR_READ_MASK);
	}
	/* Mask NACK and RXRDY interrupts. */
	twim_it_mask = AVR32_TWIM_IER_STD_MASK | AVR32_TWIM_IER_RXRDY_MASK;
	/* Update IMR through IER. */
	twim_inst->ier = twim_it_mask;
	/* Enable master transfer. */
	twim_inst->cr = AVR32_TWIM_CR_MEN_MASK;
	/* Enable all interrupts. */
	cpu_irq_enable ();
	/* Get data. */
	while (!(transfer_status) && !(twim_status ())) {
		cpu_relax();
	}
	/* Disable master transfer. */
	twim->cr = AVR32_TWIM_CR_MDIS_MASK;
	/* Check for nack. */
	if (transfer_status == TWI_RECEIVE_NACK || transfer_status == TWI_ARBITRATION_LOST) {
		return TWIM_ERR_IO_ERROR;
	}
	return TWIM_STATUS_OK;
}

/**
 * \brief Write multiple bytes to a TWI compatible slave device
 *
 * \param twin           		Base address of the TWIM (i.e. &AVR32_TWIM)
 * \param *package        		Package information and data
 *                        		(see \ref twim_package_t)
 * \retval TWIM_STATUS_OK		If all bytes were send successfully
 * \retval TWIM_ERR_IO_ERROR	NACK received or Bus Arbitration lost
 * \retval TWIM_ERR_TIMEOUT		Peripheral is being busy.
 */
twim_status_code_t twim_write_packet (volatile avr32_twim_t *twim, const twim_package_t *package)
{
	uint8_t _timeout;

	/* Wait until peripheral is free. */
	_timeout = 100;
	while((pdFALSE == xSemaphoreTake(xTWIMSemaphore, 20)))
	{
		if(!_timeout--) {
			return TWIM_ERR_TIMEOUT;
		}
	}

	/* Reset the TWIM module to clear the THR register. */
	twim->cr = AVR32_TWIM_CR_MEN_MASK;
	twim->cr = AVR32_TWIM_CR_SWRST_MASK;
	twim->cr = AVR32_TWIM_CR_MDIS_MASK;
	/* Set pointer to TWIM instance for IT. */
	twim_inst = twim;
	/* Disable the TWIM interrupts. */
	twim_disable_interrupt (twim_inst);
	/* Initialize bus transfer status. */
	transfer_status = TWI_SUCCESS;
	/* mask NACK and TXRDY interrupts. */
	twim_it_mask = AVR32_TWIM_IER_STD_MASK | AVR32_TWIM_IER_TXRDY_MASK;
	/* Set next transfer to false. */
	twim_next = false;
	/* Check if internal address access is performed. */
	if (package->addr_length) {
		/* Selection of first valid byte of the address. */
		twim_tx_data = package->addr;
		/* Set the number of bytes to transmit. */
		twim_tx_nb_bytes = package->addr_length;
		/* Set next transfer to true. */
		twim_next = true;
		/* Set the number of bytes & address for next transfer. */
		twim_package = package;
	}
	else {
		/* Get a pointer to applicative data. */
		twim_tx_data = package->buffer;
		/* Get a copy of nb bytes to write. */
		twim_tx_nb_bytes = package->length;
	}

	/* Initiate the transfer to send the data. */
	twim->cmdr = (package->chip << AVR32_TWIM_CMDR_SADR_OFFSET)
			| ((package->length + package->addr_length) << AVR32_TWIM_CMDR_NBYTES_OFFSET)
			| (AVR32_TWIM_CMDR_VALID_MASK)
			| (AVR32_TWIM_CMDR_START_MASK)
			| (AVR32_TWIM_CMDR_STOP_MASK)
			| (0 << AVR32_TWIM_CMDR_READ_OFFSET);
	/* Update IMR through IER. */
	twim_inst->ier = twim_it_mask;
	/* Enable master transfer. */
	twim_inst->cr = AVR32_TWIM_CR_MEN_MASK;
	/* Enable all interrupts. */
	cpu_irq_enable ();
	/* Send data. */
	while (!(transfer_status) && !(twim_status ())) {
		cpu_relax();
	}
#if AVR32_TWIM_H_VERSION > 101	//Removed in twim100 module due to IC bug
	/* Disable master transfer. */
	twim->cr = AVR32_TWIM_CR_MDIS_MASK;
#endif
	// Check for nack
	if (transfer_status == TWI_RECEIVE_NACK || transfer_status == TWI_ARBITRATION_LOST) {
		return TWIM_ERR_IO_ERROR;
	}
	return TWIM_STATUS_OK;
}

/**
 * \brief Write multiple bytes to a TWI compatible slave device
 *
 * \param twim					Base address of the TWIM (i.e. &AVR32_TWIM).
 * \param *buffer				Data to be transmitted
 * \param nbytes				Number of bytes to be transmitted
 * \param saddr					Slave address
 * \param tenbit				Ten bit addressing
 * \retval TWIM_STATUS_OK		If all bytes were send successfully
 * \retval TWIM_ERR_IO_ERROR	NACK received or Bus Arbitration lost
 * \retval TWIM_ERR_TIMEOUT		Peripheral is being busy.
 */
twim_status_code_t twim_write(volatile avr32_twim_t *twim, uint8_t const *buffer, uint32_t nbytes, uint32_t saddr, bool tenbit)
{
	uint8_t _timeout;

	/* Wait until peripheral is free. */
	_timeout = 100;
	while((pdFALSE == xSemaphoreTake(xTWIMSemaphore, 20)))
	{
		if(!_timeout--) {
			return TWIM_ERR_TIMEOUT;
		}
	}

	/* Reset the TWIM module to clear the THR register. */
	twim->cr = AVR32_TWIM_CR_MEN_MASK;
	twim->cr = AVR32_TWIM_CR_SWRST_MASK;
	twim->cr = AVR32_TWIM_CR_MDIS_MASK;
	/* Set pointer to TWIM instance for IT. */
	twim_inst = twim;
	/* Disable the TWIM interrupts. */
	twim_disable_interrupt (twim_inst);
	/* Get a pointer to applicative data. */
	twim_tx_data = buffer;
	/* Set the number of bytes to transmit. */
	twim_tx_nb_bytes = nbytes;
	/* Set next transfer to false. */
	twim_next = false;
	/* Initialize bus transfer status. */
	transfer_status = TWI_SUCCESS;
	/* Set the command to start the transfer. */
	twim_inst->cmdr = (saddr << AVR32_TWIM_CMDR_SADR_OFFSET)
			| (nbytes << AVR32_TWIM_CMDR_NBYTES_OFFSET)
			| (AVR32_TWIM_CMDR_VALID_MASK)
			| (AVR32_TWIM_CMDR_START_MASK)
			| (AVR32_TWIM_CMDR_STOP_MASK)
			| ((tenbit ? 1 : 0) << AVR32_TWIM_CMDR_TENBIT_OFFSET)
			| (0 << AVR32_TWIM_CMDR_READ_OFFSET);
	/* Mask NACK and TXRDY interrupts. */
	twim_it_mask = AVR32_TWIM_IER_NAK_MASK | AVR32_TWIM_IER_TXRDY_MASK;
	/* Update IMR through IER. */
	twim_inst->ier = twim_it_mask;
	/* Enable master transfer. */
	twim_inst->cr = AVR32_TWIM_CR_MEN_MASK;
	/* Enable all interrupts. */
	cpu_irq_enable ();
	/* Send data. */
	while (!(transfer_status) && !(twim_status ())) {
		cpu_relax();
	}
#if AVR32_TWIM_H_VERSION > 101	// Removed in twim100 module due to IC bug
	/* Disable master transfer. */
	twim->cr = AVR32_TWIM_CR_MDIS_MASK;
#endif
	if (transfer_status == TWI_RECEIVE_NACK || transfer_status == TWI_ARBITRATION_LOST) {
		return TWIM_ERR_IO_ERROR;
	}
	return TWIM_STATUS_OK;
}

/**
 * \brief Perform Chained transfers to a TWI compatible slave device
 *
 * \param twim            		Base address of the TWIM (i.e. &AVR32_TWIM)
 * \param *first          		Information regarding first transfer
 * \param *second        		Information regarding second transfer
 *                        		(see \ref twim_transfer_t)
 * \param tenbit				To enable tenbit addressing
 * \retval TWIM_STATUS_OK		Chain transfer successful
 * \retval TWIMERR_IO_ERROR		NACK received or Bus Arbitration lost
 * \retval TWIM_ERR_TIMEOUT		Peripheral is being busy.
 */
twim_status_code_t twim_chained_transfer(volatile avr32_twim_t *twim, volatile twim_transfer_t *first, volatile twim_transfer_t *second, bool tenbit)
{
	uint8_t _timeout;

	/* Wait until peripheral is free. */
	_timeout = 100;
	while((pdFALSE == xSemaphoreTake(xTWIMSemaphore, 20)))
	{
		if(!_timeout--) {
			return TWIM_ERR_TIMEOUT;
		}
	}

	/* Reset the TWIM module to clear the THR register. */
	twim->cr = AVR32_TWIM_CR_MEN_MASK;
	twim->cr = AVR32_TWIM_CR_SWRST_MASK;
	twim->cr = AVR32_TWIM_CR_MDIS_MASK;
	/* Set pointer to TWIM instance for IT. */
	twim_inst = twim;
	/* Disable the TWIM interrupts. */
	twim_disable_interrupt (twim_inst);
	/* Set next transfer to false. */
	twim_next = false;
	transfer_status = TWI_SUCCESS;
	if (tenbit && first->read) {
		twim->cmdr = (first->chip << AVR32_TWIM_CMDR_SADR_OFFSET)
				| (0 << AVR32_TWIM_CMDR_NBYTES_OFFSET)
				| (AVR32_TWIM_CMDR_VALID_MASK)
				| (AVR32_TWIM_CMDR_START_MASK)
				| (0 << AVR32_TWIM_CMDR_STOP_OFFSET)
				| (AVR32_TWIM_CMDR_TENBIT_MASK)
				| (0 << AVR32_TWIM_CMDR_READ_OFFSET);

		twim->ncmdr = (first->chip << AVR32_TWIM_CMDR_SADR_OFFSET)
				| (first->length << AVR32_TWIM_CMDR_NBYTES_OFFSET)
				| (AVR32_TWIM_CMDR_VALID_MASK)
				| (AVR32_TWIM_CMDR_START_MASK)
				| (0 << AVR32_TWIM_CMDR_STOP_OFFSET)
				| (AVR32_TWIM_CMDR_TENBIT_MASK)
				| (AVR32_TWIM_CMDR_REPSAME_MASK)
				| (AVR32_TWIM_CMDR_READ_MASK);
		while (!(twim->sr & AVR32_TWIM_SR_CCOMP_MASK)) {
			cpu_relax();
		}
		twim->scr = AVR32_TWIM_SR_CCOMP_MASK;
	}
	else {
		twim->cmdr = (first->chip << AVR32_TWIM_CMDR_SADR_OFFSET)
				| (first->length << AVR32_TWIM_CMDR_NBYTES_OFFSET)
				| (AVR32_TWIM_CMDR_VALID_MASK)
				| (AVR32_TWIM_CMDR_START_MASK)
				| (0 << AVR32_TWIM_CMDR_STOP_OFFSET)
				| ((tenbit ? 1 : 0) << AVR32_TWIM_CMDR_TENBIT_OFFSET)
				| ((first->read ? 1 : 0) << AVR32_TWIM_CMDR_READ_OFFSET);
	}

	twim->ncmdr = (second->chip << AVR32_TWIM_CMDR_SADR_OFFSET)
			| (second->length << AVR32_TWIM_CMDR_NBYTES_OFFSET)
			| (AVR32_TWIM_CMDR_VALID_MASK)
			| (AVR32_TWIM_CMDR_START_MASK)
			| (AVR32_TWIM_CMDR_STOP_MASK)
			| ((tenbit ? 1 : 0) << AVR32_TWIM_CMDR_TENBIT_OFFSET)
			| (((tenbit && second->read) ? 1 : 0) << AVR32_TWIM_CMDR_REPSAME_OFFSET)
			| ((second->read ? 1 : 0) << AVR32_TWIM_CMDR_READ_OFFSET);

	if (first->read) {
		/* Get a pointer to applicative data. */
		twim_rx_data = first->buffer;
		/* Get data. */
		while (!(twim->sr & AVR32_TWIM_SR_CCOMP_MASK)) {
			if (twim->sr & AVR32_TWIM_SR_RXRDY_MASK) {
				*twim_rx_data++ = twim->rhr;
			}
		}
		if (twim->sr & AVR32_TWIM_SR_RXRDY_MASK) {
			*twim_rx_data++ = twim->rhr;
		}
	}
	else {
		/* Get a pointer to applicative data. */
		twim_tx_data = first->buffer;
		twim_tx_nb_bytes = first->length;
		/* Send data. */
		while (!(twim->sr & AVR32_TWIM_SR_CCOMP_MASK)) {
			if ((twim_tx_nb_bytes > 0) &&
					(twim->sr & AVR32_TWIM_SR_TXRDY_MASK)) {
				twim->thr = *twim_tx_data++;
				twim_tx_nb_bytes--;
			}
		}
	}

	twim->scr = AVR32_TWIM_SR_CCOMP_MASK;

	if (second->read) {
		/* Get a pointer to applicative data. */
		twim_rx_data = second->buffer;
		/* Get data. */
		while (!(twim->sr & AVR32_TWIM_SR_IDLE_MASK)) {
			if (twim->sr & AVR32_TWIM_SR_RXRDY_MASK) {
				*twim_rx_data++ = twim->rhr;
			}
		}
	}
	else {
		/* Get a pointer to applicative data. */
		twim_tx_data = second->buffer;

		twim_tx_nb_bytes = second->length;
		/* Send data. */
		while (!(twim->sr & AVR32_TWIM_SR_IDLE_MASK)) {
			if ((twim_tx_nb_bytes > 0) &&
					(twim->sr & AVR32_TWIM_SR_TXRDY_MASK)) {
			twim->thr = *twim_tx_data++;
			twim_tx_nb_bytes--;
			}
		}
	}

	if (twim->sr & AVR32_TWIM_SR_ARBLST_MASK) {
		twim->scr = AVR32_TWIM_SCR_ARBLST_MASK;
		return TWIM_ERR_IO_ERROR;
	}

	if (twim->sr & AVR32_TWIM_SR_NAK_MASK) {
		twim->cmdr = twim->cmdr ^ AVR32_TWIM_CMDR_VALID_MASK;
		twim->scr = AVR32_TWIM_SCR_NAK_MASK;
		return TWIM_ERR_IO_ERROR;
	}
	return TWIM_STATUS_OK;
}

/**
 * \brief Information about the current status of the TWI Bus
 */
uint8_t twim_status (void)
{
	uint32_t status = twim_inst->sr;
	if ((status & AVR32_TWIM_SR_IDLE_MASK)) {
		return 1;
	}
	else {
		return 0;
	}
}

#endif /* BOARD_1_0_USED */